﻿// <copyright file="Face.cs" company="Community Combat Simulator">
//    Community Combat Simulator: a free combat flight simulator.
//    Copyright (C) 2008 Aaron Schinkowitch
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see http://www.gnu.org/licenses/.
// </copyright>
namespace CCSim.Vecmath
{
    using System;

    /// <summary>
    /// Description of Face.
    /// </summary>
    public class Face
    {
        /// <summary>
        /// The face's first vertex.
        /// </summary>
        private Vector vertex1;
        
        /// <summary>
        /// The face's second vertex.
        /// </summary>
        private Vector vertex2;
        
        /// <summary>
        /// The face's third vertex.
        /// </summary>
        private Vector vertex3;
        
        /// <summary>
        /// The face's normal vector.
        /// </summary>
        private Vector normal;
        
        /// <summary>
        /// Initializes a new instance of the Face class for the specified vertices. The face's 
        /// normal is computed using standard winding.
        /// </summary>
        /// <param name="v1">The first vertex.</param>
        /// <param name="v2">The second vertex.</param>
        /// <param name="v3">The third vertex.</param>
        public Face(Vector v1, Vector v2, Vector v3)
        {
            this.Vertex1 = v1;
            this.Vertex2 = v2;
            this.Vertex3 = v3;
            
            this.Normal = (v1 - v2).Cross(v3 - v1).Normal;
        }
        
        /// <summary>
        /// Gets the face's normal.
        /// </summary>
        /// <value>The face's normal vector.</value>
        public Vector Normal 
        {
            get { return this.normal; }
            
            private set { this.normal = value; }
        }
        
        /// <summary>
        /// Gets or sets the first vertex of the face.
        /// </summary>
        internal Vector Vertex1 
        {
            get 
            { 
                return this.vertex1; 
            }
            
            set 
            {
                if (value == null) 
                {
                    throw new ArgumentNullException("value", "Vertex1 cannot be null");
                }
                
                this.vertex1 = value; 
            }
        }

        /// <summary>
        /// Gets or sets the face's second vertex.
        /// </summary>
        internal Vector Vertex2 
        {
            get 
            {
                return this.vertex2; 
            }
            
            set 
            {
                if (value == null) 
                {
                    throw new ArgumentNullException("value", "Vertex2 cannot be null");
                }
            
                this.vertex2 = value;
            }
        }
        
        /// <summary>
        /// Gets or sets the face's third vertex.
        /// </summary>
        internal Vector Vertex3 
        {
            get 
            { 
                return this.vertex3;
            }
            
            set
            {
                if (value == null) 
                {
                    throw new ArgumentNullException("value", "Vertex3 cannot be null");
                }
            
                this.vertex3 = value;
            }
        }

        /// <summary>
        /// Gets a string representation of the face.
        /// </summary>
        /// <returns>A string representation of the face.</returns>
        public override string ToString()
        {
            return GetType().Name + " (" + this.Vertex1 + ", " + this.Vertex2 + ", " 
                + this.Vertex3 + ")";
        }
        
        /// <summary>
        /// Checks if the face is equal to another object.
        /// </summary>
        /// <param name="obj">The other object.</param>
        /// <returns>true if the other object is an equal face, false otherwise.</returns>
        public override bool Equals(object obj)
        {
            Face other = obj as Face;
                        
            return other != null && this.Vertex1.Equals(other.Vertex1) 
                && this.Vertex2.Equals(other.Vertex2) && this.Vertex3.Equals(other.Vertex3) 
                && this.Normal.Equals(other.Normal);
        }

        /// <summary>
        /// Gets a hash code for the face.
        /// </summary>
        /// <returns>A hash code.</returns>
        public override int GetHashCode()
        {
            return this.Vertex1.GetHashCode() ^ this.Vertex2.GetHashCode() 
                ^ this.Vertex3.GetHashCode();
        }
    }
}
